#define __ASSEMBLY__
#include "config.h"

#define SPL_RAM_ADDRESS         0xA3C00000
#define G4_BaseAddress          0x00000000
#define SPL_SIZE                0x400
#define SPL_SIGN                0x544F4F42

@----- DiskOnChip G4 registers -----------------
#define CDSN_IO                 0x0800
#define CDSN_IO_CORR            0x02
#define CDSN_CNTR               0x1000
#define G4_BaseAddressIO        G4_BaseAddress+CDSN_IO
#define G4_BaseAddressCNTR      G4_BaseAddress+CDSN_CNTR
#define G4_NNOPreg              0x3E
#define G4_NDOCcontrol          0x0C
#define G4_NDOCcontrolConfirm   0x72
#define G4_NdeviceSelect        0x0A
#define G4_NflashSequence       0x32
#define G4_NflashCommand        0x34
#define G4_NflashAddress        0x36
#define G4_NflashControl        0x38
#define G4_NflashData           0x3C
#define G4_NflashDataByte       0x52
#define G4_PipelineReg          0x50
#define G4_NECCcontrol_0        0x40
#define G4_NECCcontrol_1        0x42
#define G4_EndOfDataReg         0x1E
#define G4_Configuration        0x0E
@------------ EDC modes ----------------------------------------
#define G4_EDC_ERROR_MASK       0x80
#define G4_EDC_VAL_527          0x920F
#define G4_EDC_VAL_4            0x8004
@----- Flash Commands ------------------------------------------
#define RESET_FLASH_CMD         0xFF
#define READ_A_FLASH_CMD        0x00
#define MULTI_READ_CMD          0x30
#define SET_RELIABLE_FIRST_CMD  0xA3
#define SET_RELIABLE_SECOND_CMD 0x22
@----- Flash Sequences ------------------------------------------
#define G4_ResetFlash_Seq       0x00
#define G4_READ_Seq             0x03
#define G4_Reliable_Seq         69
@------------ Bits for reading CDSN_Conrol_Status --------------
#define G4_RB_SHIFT             31
#define G4_RB                   0x1
@------------ Bits for writing to Flash_Control_register -----------
#define G4_CDSN_CE              0x59
@------------ Bits for reading Flash_Control_Reg ----------
#define G4_ACCESS_ERR           0x06
@------------ ASIC modes ---------------------------------------
#define DOC_CTRL_NORMAL_MODE    0x05
@------------ Bit Distance -------------------------------------
#define G4_BIT_DISTANCE         3
@------------ Data Define --------------------------------------
#define TRUE                    1
#define FALSE                   0
#define BLOCK_DATA              0x200
#define SECTOR_AND_EXTRA        0x210
#define G4_EDC_DATA             0x0E
#define G4_PAGE_OFFSET          0x108
#define G4_SIGN_OFFSET          0x100

#define G4_SPL_NEXT             0x80

#define G4_CHIP_ID              0x0400
#define G4_PAGES_IN_REL_UNIT    0x40
#define G4_PAGES_IN_UNIT        0x80
#define G4_SECTORS_IN_REL_UNIT  0x80

#define BAUD_4800    0xC0
#define BAUD_9600    0x60
#define BAUD_19200   0X30
#define BAUD_38400   0x18
#define BAUD_57600   0x10
#define BAUD_115200  0X08


#define TDRQ     0x20
#define TEMT     0x40
#define DR       0x01
#define DLAB     0x80
#define nBT_OFF  0x100
#define BTDTR    0x80


.section .text.init
    /* Jump vector table as in table 3.1 in [1] */
.globl _mainCRTStartup
_mainCRTStartup:    b   reset
    b   undefined_instruction
    b   software_interrupt
    b   abort_prefetch
    b   abort_data
    b   not_used
    b   irq
    b   fiq

reset:
     mov    r0, #0x13   // set into Supervisior mode
     orr    r0, r0, #0xC0   // disable IRQ, FIQ
     msr    cpsr, r0

#if 1
    mov     r0, pc
    cmp     r0, #0x800
    bhi     RAMBEGIN
#endif

     bl Init_GPIO

     bl Init_INT
//The following is added by Bill Chen
    ldr     r0,  =PWR_BASE_PHYSICAL
    ldr     r10, [r0, #RCSR_OFFSET]
    mov     r2,  #RCSR_ALL      // Mask RCSR
    and     r10,  r10,  r2      // r10 now holds the conditioned Reset Reason
    teq     r10, #RCSR_SLEEP_RESET
    beq     7f
//
     bl     Init_Clocks

7:
     bl     Init_Uart

     mov    r2, #0x61
     bl UartPrintch

     bl     Init_Mem

    /* enable ICache and DCache and BTB */
    mrc p15, 0, r0, c1, c0, 0
    mov r1, #0x1800
    orr r1, r1, #0x4
    orr r0, r0, r1
    mcr p15, 0, r0, c1, c0, 0

     mov    r2, #0x62
     bl UartPrintch

     bl mdoc_copy



/* #endif */

RAMBEGIN:

    mov r2, #0x31
    bl  UartPrintch

    @adr     r3,  str_cpspl   @ FRQ Interrupt Mesage
    @bl      UartPrintStr


    /* Set up the user and irq stack pointer */
    ldr r1, =M_START
    ldr r2, =M_STACK_END_OFFSET_FROM_RAM_START
    add r1, r1, r2
    sub sp, r1, #0x1000 /* set IRQ sp : 0x100 bytes lower from the IRQ sp */
            /* If you need more stack space in interrupt, you can increase this value (0x100) to much as you want */

    /* Jump to the C code */
    /* from here, copy the main code from flash to RAM.
     * interrupt vector contents should be changed,
     * as they use bl or other method for communication
     * this code should be modified to jump to #0xc?????
     * as we need to jump from flash to RAM
     */
    /* check copy from 16 bits to 32 bits */

    /* copy data from the flash to ram */
    /*
     *       Flash 16MBx16bits (32MB)       SDRAM 16MBx16bits (32MB)
     *       +----------+               r9->+----------+
     *       |          |                   |   Stack  |
     *       |          |               r8->|..........|
     *       |          |                   |          |
     *       |          |                   |BootLoader|
     *       |          |                   |          |
     *       |          |         r6,r7(1)->|..........|
     *       |          |                   |          |
     *       |          |                   |          |
     *       |          |                   |          |
     *       |          |                   |          |
     *       |          |                   |          |
     *       |          |                   |          |
     *       |          |                   |          |
     *       |          |                   |          |
     *       |          |                   |          |
     *       |----------| --                |          |
     *       |          | /\                |          |
     *       |BootLoader| ||                |          |
     *       |          | \/                |          |
     *       +----------+ --         r7(0)->+----------+
     *
     */
    /* clear the BSS section */
    ldr r1, bss_start
    ldr r0, bss_end
    sub r0, r0, r1

    /* r1 = start address */
    /* r0 = *number of bytes */
    mov r2, #0
    mov r3, #0
    mov r4, #0
    mov r5, #0

clear_bss:
    stmia   r1!, {r2,r3,r4,r5}
    subs    r0, r0, #16
    bne clear_bss

    mov r2, #0x32
    bl  UartPrintch

    bl  _c_main

    /* The c code should never return ! */
    b   reset


infinite_loop:
    b infinite_loop

undefined_instruction:
    b   undefined_instruction

software_interrupt:
    b   software_interrupt

abort_prefetch:
    b   abort_prefetch

abort_data:
    b   abort_data

not_used:
    b   not_used

irq:
    sub lr, lr, #4
    ldr sp, =M_STACK_END_OFFSET_FROM_RAM_START
    add sp, sp, #RAM_START  /* I cannot load the value to other register */
                /* so #RAM_START is still restricted */
    stmfd sp!, {r0-r12,lr}

    ldr r1, =M_START
    ldr r2, =M_BOOT_LOADER_AREA_START_OFFSET_FROM_RAM_START
    add r1, r1, r2
    add pc, pc, r1 /* now jump to ram */
    mov r1, r1 /* pc advances 2 instructions further */
    mov r1, r1
    mov r1, r1
    bl  _c_irq
    ldmfd sp!, {r0-r12,pc}^

fiq:
    b   fiq


@If system boot from MDOC,do nessary mdoc init within the bound of 2k binary code size

@=========================================================================
@   IPL example code - ARM 32
@
@  Sequence:
@    1. Check type of Reset: (to be added by customer)
@         (Hard Reset, Soft Reset, Sleep / Resume Reset, WatchDog Reset)
@    2. In case of Soft or Sleep / Resume Reset Jump to specific RAM location,
@         in case of Hard or WatchDog Reset Continue IPL Steps
@    3. Minimal H/W Init: (to be added by customer)
@         (Set phase-locked loop (PLL) in PPCR, Setup all nesessary CSx lines)
@    4. Enable system RAM: (to be added by customer)
@         (Init Memory Controller)
@    5. Copy IPL To System RAM
@    6. Jump to IPL code in RAM
@    7. Copy SPL code from DiskOnChip Flash to system RAM
@    8. Jump to SPL code for further system initialization and loading
@
@  Note:
@    The code should NOT be used with DOC2000, DOC 2000 TSOP and MDOC
@
@  TODO#:
@    1. Define Features: SPL_MODE, etc...
@    2. Define your MDOC+ window relevant address bits
@    3. Define your System RAM loacation for storing IPL and SPL code
@    4. Set your SPL size (default is 16 Kbytes)
@    5. Set SPL signature (default is BIPO)
@    6. Insert your chipset IPL code (system initialization sequence (1) - (4))
@

@=========================================================================



@===============================================================
@ TODO #1 - Define Features
@===============================================================


mdoc_copy:


@----- Registers Usage: ----------------------------------------
@ r0  - temp0
@ r1  - temp1 - CDSN_IO (offset 0x800) and CDSN_CNTR (offset 0x1000)
@ r2  - temp2
@ r3  - current page pointer (page address)
@ r4  - sector counter
@ r5  - offset in page in sectors
@ r6  - functions parameter 1
@ r7  - temp4 - functions parameter 2
@ r8  - page offset
@ r9  - page in unit mask
@ r10 - return address
@ r11 - SPL Size
@ r12 - pointer to SPL in RAM
@ r13 - in FL_FUNC_MODE = return address
@---------------------------------------------------------------
@ 1. Setup destination before copying SPL and Size
@---------------------------------------------------------------
@    IF FL_FUNC_MODE
@        mov     r11, r0                 @ Get SPL Size
@        mov     r12, r1                 @ Get SPL Address
@    ELSE
        mov     r11, #SPL_SIZE          @ Number of 512 byte pages
        ldr     r12, =SPL_RAM_ADDRESS   @ Address for SPL
@   ENDIF
@---------------------------------------------------------------
@ 2. Init pointers to CDSN_IO and CDSN_CONTROL area
@       mov     r1, #CDSN_IO            @ pointer to CDSN_IO (offset 0x800)
@---------------------------------------------------------------
    @ set DiskOnChip window
        ldr     r1, =G4_BaseAddressCNTR
@---------------------------------------------------------------
G4_start_of_ipl_copy:

@---------------------------------------------------------------
@ 3. Load Sector counter with start value
@---------------------------------------------------------------

        mov     r4, #2

get_normal:
@---------------------------------------------------------------
@ 4. Get Asic ready
@---------------------------------------------------------------
@       ldrb    r2, [r1, #G4_NDOCcontrol]   @ First Time Access
@
@ get into normal mode
@
        mov     r2, #DOC_CTRL_NORMAL_MODE
        strb    r2, [r1, #G4_NDOCcontrol]   @ 5 -> 100c
        mvn     r2, r2                      @ move NOT
        strb    r2, [r1, #G4_NDOCcontrolConfirm] @ FA ->  1072

@ inhibit boot detector
        mov     r2, #0xC
        strb    r2, [r1, #G4_Configuration]   @ inhibit boot detector

        mov     r9, #(G4_SECTORS_IN_REL_UNIT - 1)

        mov     r3,#0x280                   @ r3 (=flash addr) points to unit 5.

        mov     r5,#0x0                     @ column address in sectors [0,1,2,3]

@---------------------------------------------------------------
@ read chip ID
@---------------------------------------------------------------
read_chip_id:

        mov     r2, #0
        ldrh    r2, [r1]                    @ Read chip ID.
        ldrh    r2, [r1]                    @ Read chip ID.
        cmp     r2, #0x400                  @ compare to g4 chip id
        bne     NoDocFound

        strb    r1, [r1,#G4_NdeviceSelect]  @ Set Floor 0

        mov     r0, #G4_CDSN_CE             @ set WP | CE
        strb    r0, [r1, #G4_NflashControl]
@---------------------------------------------------------------
@ 5. Look for SPL start
@---------------------------------------------------------------
G4_FindNextUnit:
    @
    @ Reset sequence
    @
    @ Clean Access Error
        mov     r7, #G4_ResetFlash_Seq      @ Reset Sequence cmd-0,addr,cmd-30
        mov     r6, #RESET_FLASH_CMD        @ Reset Command
        bl      G4_SendCommandAndSeq
        bl      G4_WaitForReady

    @
    @ Set Reliable sequence
    @
        mov     r7, #G4_Reliable_Seq          @ Set reliable Sequence
        strb    r7, [r1, #G4_NflashSequence]  @ Send Sequence
        mov     r6, #SET_RELIABLE_FIRST_CMD   @ reliable first Command
        strb    r6, [r1, #G4_NflashCommand]   @ Send Command
        mov     r6, #SET_RELIABLE_SECOND_CMD  @ reliable second Command
        strb    r6, [r1, #G4_NflashCommand]   @ Send Command

        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]

G4_continue_search:
    @
    @ increase address
    @
        add     r3, r3, #G4_SPL_NEXT        @ r3 cotain start SPL flash-addr.go to next unit: add 80H to address

    @ Read Signature
        mov     r8, #0x100
        bl      G4_ReadCommandInit          @ send read seq and command and addr

    @ Check For Protection Error
        ldrb    r0, [r1, #G4_NflashControl]
        ldrb    r0, [r1, #G4_NflashControl]
        tst     r0, #G4_ACCESS_ERR          @ CPSR <- r0 & 0x06
        bne     G4_FindNextUnit             @ skip unit in case of protection violation

        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]


    @ Set Signature Offset
        ldr     r7, =G4_EDC_VAL_4
        bl      G4_ReadCommandContinue      @ CMD 30 , wait for R/B , set ECC CTRL reg
        ldr     r6, =SPL_SIGN
    @
    @ Reading from CDSN IO - 4 bytes of data (signature)
    @
        ldrh    r0, [r1,#G4_NflashData]      @ DON'T REMOVE IT!
        ldrh    r0, [r1,#G4_NflashData]      @ first actual read
        ldrh    r2, [r1,#G4_PipelineReg]     @ second actual read

        mov     r2 ,r2, LSL #16
        orr     r0, r0, r2

    @ write to end of data reg
        mov     r2, #0
        strb    r2, [r1, #G4_EndOfDataReg]
        strb    r0, [r1,#G4_NNOPreg]

        eors    r6, r6, r0                    @ xor with SPL_SIGN
        beq     G4_Read_A_Area_start          @ jump if found

     @ SPL_SIGN not equal
     @ Calculate "Bit Distance" in r0
     @
        eor r0, r0, r0                        @ r0 <- 0
G4_sign_loop:
        mov     r2, #0x01
        tst     r6, #0x01                     @ r6 contain 1 were it differ fron signiture
        beq     G4_continue_sign
        add     r0, r0, #1                    @ difference found
G4_continue_sign:
        movs    r6, r6, LSR #1                @ Shift right r6
        bne     G4_sign_loop
        cmp     r0, #G4_BIT_DISTANCE
        bcs     G4_continue_search            @ r0 >= 3
@---------------------------------------------------------------
@ 6. Issue READ command
@---------------------------------------------------------------
@
@ we found good signiture
@
G4_Read_A_Area_start:
        mov     r0, #0                       @ Set Page Offset 0
        mov     r8, r0
        b       G4_Read_start

G4_change_column_addr:
    @
    @  insert new offset into r8
    @
        mov     r2, #0x108                   @ in words
        mul     r8, r5, r2                   @ r8 = r5 * r2

G4_Read_start:

        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]

        bl      G4_ReadCommandInit           @ send read seq and command and addr
        ldr     r7, =G4_EDC_VAL_527
        bl      G4_ReadCommandContinue       @ CMD 30 , wait for R/B , set ECC CTRL reg

@---------------------------------------------------------------
@ 7. Read first 512 bytes
@---------------------------------------------------------------
    @ Init amount of data to read
        ldr     r0, =0x20E

    @ Read 512 bytes of data + 8 bytes Signature + 7 bytes of EDC + 1

        ldrh    r2, [r1, #G4_NflashData]     @ unused

G4_Read_first_512bytes:
        ldrh    r2, [r1, #G4_NflashData]     @ r2  <-- [NflashData]
        strh    r2, [r12]                    @ [r12] <-- r2
        add     r12,r12,#2                   @ r12 = r12 + 2
        subs    r0, r0, #2
        bne     G4_Read_first_512bytes

        ldrh    r2, [r1,#G4_PipelineReg]     @ last read
        strh    r2, [r12]                    @ [r12] <-- r2 . store to ram

        strb    r0, [r1,#G4_NNOPreg]
        strb    r0, [r1,#G4_NNOPreg]
    @
    @ write to end of data reg
    @
        mov     r2, #0
        strb    r2, [r1, #G4_EndOfDataReg]

        strb    r0, [r1,#G4_NNOPreg]
        strb    r0, [r1,#G4_NNOPreg]

        sub     r12, r12, #G4_EDC_DATA      @ Restore r12 to SPL Addr



        @ Check if even or odd page is read
        @ EDC mode is applied only to even page
        @
        @ Check ECC
        @
        ldrb    r0, [r1,#G4_NECCcontrol_1]
        ldrb    r0, [r1,#G4_NECCcontrol_1]
        mov     r2, #G4_EDC_ERROR_MASK
        tst     r0, r2
        beq     G4_NoEdcErrorA              @ if and result is 0 - NO ECC error - jump
        @
        @ We have edc error !
        @

        cmp     r5,#0                       @ if its s0 - advance with 1 sector
        beq     check_4
        cmp     r5,#2                       @ if its s1 - advance with 1 sector
        beq     check_4
        cmp     r5,#1                       @ if its c0 - advance with 1 sector
        bne     check_5
        mov     r5,#0                       @ its c1 - move 0 to column and goto next page
        b       G4_read_Next
check_5:
        add     r5,r5,#1                    @ advance with 1 sector
        b       G4_change_column_addr
check_4:
        add     r5,r5,#1                    @ advance with 1 sector
        sub     r12, r12, #BLOCK_DATA       @ so we won't use the bad data
        b       G4_change_column_addr


G4_NoEdcErrorA:
        @
        @ the scheme of the sectors is : s0 , c0 , s1 , c1
        @                                s2 , c2 , s3 , c3
        @
        @ sector was read OK
        @
        cmp     r5,#0                       @ if it s0 - advance with 2 sectors
        bne     check_1
        add     r5,r5,#2
        b       G4_change_column_addr
check_1:
        cmp     r5,#1
        bne     check_2
        add     r5,r5,#1                    @ if it c0 - advance with 1 sector
        b       G4_change_column_addr
check_2:
        mov     r5,#0x0                     @ if it s1 or c1 - column=0,next page
        b       G4_read_Next

@---------------------------------------------------------------
@ 8. Check if SPL is already copied
@---------------------------------------------------------------
G4_read_Next:
        cmp     r4, r11                     @ did sector counter(r4) reached (r11)?
        bcs     JumpToSPL                   @ r4 >= r11
        add     r3, r3, #2                  @ page address
        and     r0, r4, r9                  @ R0 <- R4 & R9 (=G4_SECTORS_IN_REL_UNIT-1)
        add     r4, r4, #2                  @ sector counter (in 2k we have 2 sectors)
        cmp     r0, #0
        bne     G4_Read_A_Area_start        @ read in current unit
        sub     r3, r3, #G4_PAGES_IN_UNIT   @ will be incremented later
        b       G4_FindNextUnit             @ goto next unit
@---------------------------------------------------------------
@ 9. Branch to SPL located in system RAM for further initialization
@---------------------------------------------------------------
NoDocFound:
@        IF FL_FUNC_MODE
@        mov     r0, #FALSE
@        b       ReturnToCaller
@        ENDIF
JumpToSPL:

@        mov     r0, #TRUE
ReturnToCaller:

        ldr r1, =RAMBEGIN
        @ldr    r2, =SPL_RAM_ADDRESS
        @add    r1, r1, r2
        mov pc, r1
@        ldr     pc, =SPL_RAM_ADDRESS
@===============================================================
@       Send Read Command Init
@       On Entry: r8 = Page Offset,
@       On exit: r0, r6, r7, r10 destroyed
@===============================================================
G4_ReadCommandInit:
        mov     r10, lr
        mov     r7, #G4_READ_Seq            @ Read Sequence (from ROM)
        mov     r6, #READ_A_FLASH_CMD       @ read command
        bl      G4_SendCommandAndSeq
        bl      G4_SendAddress
        mov     pc, r10
@===============================================================
@       Send Read Command Continue
@       On Entry: r7 = EDC_VAL
@       On exit:  r6, r10 destroyed
@===============================================================
G4_ReadCommandContinue:
        mov     r10, lr
        mov     r6, #MULTI_READ_CMD
        bl      G4_SendCommand              @ send command 30
        bl      G4_WaitForReady

@===============================================================
@       Set EDC Mode for 512 + 15 data or for 4 bytes
@       On Entry: r7 = EDC_VAL
@===============================================================
G4_SetEdcMode:
        strh    r7, [r1,#G4_NECCcontrol_0]
    @ 6 NOPs
        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]
        strb    r7, [r1, #G4_NNOPreg]
        mov     pc, r10
@===============================================================
@       Send Command and Sequence
@       On Entry: r6 = Type of Command, r7 = Type of Sequence
@===============================================================
G4_SendCommandAndSeq:
        strb    r7, [r1, #G4_NflashSequence]  @ Send Sequence
G4_SendCommand:
        strb    r6, [r1, #G4_NflashCommand]   @ Send Command
        strb    r6, [r1, #G4_NNOPreg]
        strb    r6, [r1, #G4_NNOPreg]
        mov     pc, lr                        @ return from subroutine
@===============================================================
@       Send Address
@       On Entry:
@                 r3 = Address on flash in pages
@                 r8 = Offset in page
@       On exit: r0 destroyed
@===============================================================
G4_SendAddress:
        mov     r0, r8
        strb    r0, [r1, #G4_NflashAddress]   @ r8[0..7]   -->  CA0..CA7
        mov     r0, r0, LSR #8
        strb    r0, [r1, #G4_NflashAddress]   @ r8[8..10]  -->  CA8..CA10

        strb    r0, [r1,#G4_NNOPreg]
        @
        @ set new value to r0
        @
        mov     r0, r3                        @ mov r3 to r0
        strb    r0, [r1, #G4_NflashAddress]   @ r3[0..7]   -->  PA0..PA7
        mov     r0, r0, LSR #8
        strb    r0, [r1, #G4_NflashAddress]   @ r3[8..15]  -->  PA8..PA15

        strb    r0, [r1,#G4_NNOPreg]
        strb    r0, [r1,#G4_NNOPreg]

        mov     pc, lr
@===============================================================
@       WaitForReady
@       On exit: r0, r2 destroyed
@===============================================================
G4_WaitForReady:
    @ 8 NOPs
        mov     r2, #8
G4_WaitForNop:
        strb    r0, [r1,#G4_NNOPreg]
        subs    r2, r2, #1                     @ r2 = r2 - 1
        bne     G4_WaitForNop
    @ Wait For Ready - wait untill (value & 0x01) equals to 0x01
G4_WaitForReadyLoop:
        ldrb    r0, [r1, #G4_NflashControl]
        ldrb    r0, [r1, #G4_NflashControl]
        and     r0, r0, #G4_RB
        cmp     r0, #G4_RB
        bne     G4_WaitForReadyLoop
        mov     pc, lr



Init_Uart:

    ldr    r0,  = STUART_BASE_PHYSICAL @ use BTUART for debug port
    mov    r2,  #0x08              @ set baudrate 115200

    mov    r1,  #0x0               @ Zero out a work register
    str    r1,  [r0, #ST_IER_OFFSET]   @ Zero out Interrupt Enable Register
    str    r1,  [r0, #ST_FCR_OFFSET]   @ Zero out FIFO Control Register
    str    r1,  [r0, #ST_LCR_OFFSET]   @ Zero out Line Control Register
    str    r1,  [r0, #ST_MCR_OFFSET]   @ Zero out Modem Control Register
    str    r1,  [r0, #ST_ISR_OFFSET]   @ Zero out IR bit register
    ldr    r1,  [r0, #ST_MSR_OFFSET]   @ Read MSR once to clear bits

    mov    r1,  #0x83              @ Set up divisor latch bit (DLAB), 8 bit character, no parity, 1 stop bit
    str    r1,  [r0,  #ST_LCR_OFFSET]  @ Set DLAB bit

    str    r2,  [r0,  #ST_DLL_OFFSET]  @ set baud rate
    ldr    r1,  =0x0               @ Insure high baud rate byte is zero
    str    r1,  [r0,  #ST_DLH_OFFSET]
    ldr    r1,  [r0,  #ST_LCR_OFFSET]  @ Get LCR values
    bic    r1,  r1,   #DLAB            @ Clear DLAB bit
    str    r1,  [r0,  #ST_LCR_OFFSET]  @ Write the value back out
    mov    r1,  #0x07              @ This value will clear the TX and RX FIFOs
    str    r1,  [r0,  #ST_FCR_OFFSET]  @ ... and enabale the FIFOs for use.

    mov    r1,  #0x40              @ set unit enable bit
    str    r1,  [r0,  #ST_IER_OFFSET]  @ enable the UART
    mov    pc, lr                      @ Return to calling program

UartPrintStr:

        mov    r13, lr           @ Save the link register value
next:
        ldrb   r2,  [r3],  #1    @ Place byte into r2 & increment pointer
        cmp    r2,  #0           @ Is this byte NULL?
        beq    exit          @ Yes - take exit path
        bl     UartPrintch   @ No - Send byte out to UART
        b      next          @ Get next byte
exit:
       mov    pc,  r13           @ Return to the caller

.globl UartPrintch
UartPrintch:
      mov    pc,  lr                       @  Return to caller
      ldr    r0,  = STUART_BASE_PHYSICAL
bitset:
     ldr    r1,  [r0, #ST_LSR_OFFSET]      @  Get Line Status Register Data
      ands   r1,  r1,  #TDRQ               @  Is TDRQ (Transmit Data Request) bit set?
      beq    bitset                    @  No - loop until it is
      strb   r2,  [r0, #ST_THR_OFFSET]     @  It's ready! - output byte to buffer
      mov    pc,  lr                       @  Return to caller


@*********************************************************************************************
@
@ *************************************
@ **********                 **********
@ ********** CONFIGURE GPIOs **********
@ **********                 **********
@ *************************************
@
@ This subroutine sets up the GPIO pins in accordance with the values contained in the platform include file.
@
@ NOTES: Written for the PXA27x Processor on the Mainstone Development Platform.
@
Init_GPIO:

      ldr     r0,  =0x40E00000              @ Load the GPIO register block base address
//      ldr     r1,  =0x8800                        @ Get the pin set values for GPSR0
      ldr   r1, =0x02808800             @ //Bill 20060327
      str     r1,  [r0, #0x18]                      @ Write the GPSR0 values

//      ldr     r2,  =0x03cf0002                    @ Get the pin set values for GPSR1
      ldr     r2,  =0x03df0002                      @ Get the pin set values for GPSR1 //Bill 20060401
      str     r2,  [r0, #0x1c]                      @ Write the GPSR1 values

      ldr     r1,  =0x21fc00                    @ Get the pin set values for GPSR2
      str     r1,  [r0, #0x20]                      @ Write the GPSR2 values

      ldr     r2,  =0                           @ Get the pin set values for GPSR3
      str     r2,  [r0, #0x118]                 @ Write the GPSR3 values

      ldr     r1,  =0                           @ Get the pin clear values for GPCR0
      str     r1,  [r0, #0x24]                      @ Write the GPCR0 values

      ldr     r2,  =0                           @ Get the pin clear values for GPCR1
      str     r2,  [r0, #0x28]                      @ Write the GPCR1 values

      ldr     r1,  =0                           @ Get the pin clear values for GPCR2
      str     r1,  [r0, #0x2c]                      @ Write the GPCR2 values

      ldr     r2,  =0                           @ Get the pin clear values for GPCR3
      str     r2,  [r0, #0x124]                 @ Write the GPCR3 values

      ldr     r1,  =0xcbed6619                      @ Get the pin direction values for GPDR0
      str     r1,  [r0, #0x0c]                      @ Write the GPDR0 values

      ldr     r2,  =0xff32a9b3                      @ Get the pin direction values for GPDR1
      str     r2,  [r0, #0x10]                      @ Write the GPDR1 values

      ldr     r1,  =0x0bc5ffff                      @ Get the pin direction values for GPDR2
      str     r1,  [r0, #0x14]                      @ Write the GPDR2 values

      ldr     r2,  =0x006e1381                      @ Get the pin direction values for GPDR3
      str     r2,  [r0, #0x10c]                 @ Write the GPDR3 values

      ldr     r1,  =0x669c0000                  @ Get the pin alt function values for GAFR0_L
      str     r1,  [r0, #0x54]                  @ Write the GAFR0_L values

      ldr     r2,  =0xa5f00008                  @ Get the pin alt function values for GAFR0_U
      str     r2,  [r0, #0x58]                  @ Write the GAFR0_U values

      ldr     r1,  =0x69900e12                  @ Get the pin alt function values for GAFR1_L
      str     r1,  [r0, #0x5c]                  @ Write the GAFR1_L values

      ldr     r2,  =0xaaa07851                  @ Get the pin alt function values for GAFR1_U
      str     r2,  [r0, #0x60]                  @ Write the GAFR1_U values

      ldr     r1,  =0x02aaaaaa                  @ Get the pin alt function values for GAFR2_L
      str     r1,  [r0, #0x64]                  @ Write the GAFR2_L values

      ldr     r2,  =0x550cafc8                  @ Get the pin alt function values for GAFR2_U
      str     r2,  [r0, #0x68]                  @ Write the GAFR2_U values

      ldr     r1,  =0x565a95ff                  @ Get the pin alt function values for GAFR3_L
      str     r1,  [r0, #0x6c]                  @ Write the GAFR3_L values

//      ldr     r2,  =0x00001409                    @ Get the pin alt function values for GAFR3_U
      ldr     r2,  =0x00001401                  @ Get the pin alt function values for GAFR3_U //Modified by Bill
      str     r2,  [r0, #0x70]                  @ Write the GAFR3_U values



@
@   The RDH and PH bits on PXA27x must be set to enable updated GPIO pins.
@       These are sticky bits.
@
@     The following is commented by Bill Chen 20060608

@      ldr     r0, =0x40F00000                      @ set PMRCREGS PHYSICAL BASE
@      mov     r2, #(0x10 | 0x20)                   @ Set the PH and RDH bits to enable all GPIOs
@      str     r2, [r0, #0x04]                  @ Enable all GPIO lines

@     The above is commented by Bill Chen 20060608

/*
      ldr     r0,  =0x40E00000
      ldr     r2,  =0x59e5404e                          @ Get the pin alt function values for GAFR0_U
      str     r2,  [r0, #0x58]                                  @ Write the GAFR0_U values


      ldr     r2,  =0x20000
      str     r2,  [r0, #0x0]

      ldr     r2,  =0x20000
      str     r2,  [r0, #0xc]

      ldr     r2,  =0x28800
      str     r2,  [r0, #0x18]


*/

      mov     pc, lr                                    @ Return to calling program



@*********************************************************************************************
@*********************************************************************************************




Init_Mem:

    @  ***** STEP 1:     *****
    @
    @  Delay 200 uS
    @
//        ldr     r2,  =0x40A00000  @  Load OS timer base address
//        ldr     r3,  [r2, #0x10]  @  Fetch starting value of OSCR0
//        add     r3,  r3,  #0x300  @  Really 0x2E1 is about 200usec, so 0x300 should be plenty

    mov r2, #0x10000
xlli_3:
//  ldr     r1,  [r2, #0x10]  @  Fetch current OSCR0 value
//  cmp     r1,  r3       @  Is the timer past the time out value?
//  bmi     xlli_3        @  No - Loop until it is
    NOP
    sub r2, r2, #1
    cmp r2, #0
    bhi xlli_3

    @
    @   STEP 1 - 1st bullet:     Write MSC0, MSC1 and MSC2 (the order is not important)
    @   *******************

    @
    @        Write the memory control registers
    @
        ldr     r4,  =0x48000000 @  Get memory controller base address

        ldr     r1,  =0x7ff87ff8 @  Set the value for MSC0
        str     r1,  [r4, #0x08] @  Write the value out
        ldr     r1,  [r4, #0x08] @  Read back to latch the data

        ldr     r2,  =0x0 @  Get MSC1 setting
        str     r2,  [r4, #0x0c] @  Write the value out
        ldr     r2,  [r4, #0x0c] @  Read back to latch the data

        ldr     r1,  =0x0 @  Get MSC2 setting
        str     r1,  [r4, #0x10] @  Write the value out
        ldr     r1,  [r4, #0x10] @  Read back to latch the data


    @
    @   STEP 1 - 2nd bullet:     Write MECR, MCMEM0, MCMEM1, MCATT0, MCATT1, MCIO0, MCIO1 (order not important)
    @   *******************
    @
    @        (if required)

    @
    @   STEP 1 - 3rd bullet:     Write FLYCNFG
    @   *******************
    @
        ldr     r1,  =0x00010001        @  write FLYCNFG
        str     r1,  [r4, #0x20]
    @

    @
    @   STEP 1 - 4th bullet:     SKIPPED (used only when coming out of sleep)
    @   *******************
    @
    @      (If required, this would be a write to MDCNFG with enable bits deasserted.)

    @
    @   STEP 1 - 5th bullet:     update MDREFR settings
    @   *******************
    @
@        ldr     r2,  =0x23ca4018
        ldr     r2,  =0x23c84018
        str     r2,  [r4, #0x04]


@        ldr     r2,  =0x20ca2018
        ldr     r2,  =0x20c82018
        str     r2,  [r4, #0x04]

    @
    @  Preserve MDREFR in r2
    @

    @  ***** STEP 2 *****
    @
    @  For systems with Synchronous Flash
    @
    @        Note:   Synchronous Flash is handled in a separate xlli Functiona
    @

    @
    @  ***** STEP 3 *****
    @
    @  Clear the free run clock bits to enable the use of SDCLK for memory timing
    @
        ldr     r2,  =0x204b2018
        str     r2,  [r4, #0x04]

        ldr     r2,  =0x200b2018
        str     r2,  [r4, #0x04]
        ldr     r2,  =0x200ba018
        str     r2,  [r4, #0x04]

/* The following is added by Bill Chen 20060530 */
@   ldr r2, =0x0011e010
@   str r2, [r4, #0x04]
/*The above is added by Bill Chen 20060530*/

        nop     @  Do not remove!
        nop     @  Do not remove!
    @
    @  ***** STEP 4 *****
    @
    @  Appropriately configure, but don't enable, each SDRAM partition pair
    @
        ldr     r1, =0x08c82a55        @  Fetch platform value for MDCNFG

    bic     r1, r1,  #0x1
    bic r1, r1,  #0x2
    bic     r1, r1,  #0x10000
    bic     r1, r1,  #0x20000
        @bic     r1, r1,  #(0x1 :   OR:  0x2)      @  Disable all
        @bic     r1, r1,  #(0x10000 :   OR:  0x20000)  @  SDRAM banks


        str     r1, [r4, #0x0]         @  Write w/o enabling SDRAM banks
    @
    @  ***** STEP 5 *****  (Delay at least 200 uS)
    @
//  ldr     r2,  =0x40A00000       @  Load OS timer base address
//  ldr     r3,  [r2, #0x10]       @  Fetch starting value of OSCR0
//  add     r3,  r3,  #0x300       @  Really 0x2E1 is about 200usec, so 0x300 should be plenty

    mov r2, #0x10000
xlli_5:
//  ldr     r1,  [r2, #0x10]       @  Fetch current OSCR0 value
//  cmp     r1,  r3                @  Is the timer past the time out value?
//  bmi     xlli_5                 @  No - Loop until it is
    NOP
    sub r2, r2, #1
    cmp r2, #0
    bhi xlli_5

    @
    @  ***** STEP 6 ***** (Make sure DCACHE is disabled)
    @
        mrc     p15, 0, r2, c1, c0, 0  @  load r2 contents of register 1 in CP 15
    bic     r2,  r2,  #0x04        @  Disable D-Cache
    mcr     p15, 0, r2, c1, c0, 0  @  Write back to CP15
    @
    @  ***** STEP 7 *****
    @
    @  Access memory *not yet enabled* for CBR refresh cycles (8)
    @  - CBR is generated for all banks
    @

//The following is added by Bill Chen
    /*******************     Step 7        ********************************/
    /*  Access memory *not yet enabled* for CBR refresh cycles (8)        */
    /*  - CBR is generated for all banks                                  */
//       ldr r0, =PWR_BASE_PHYSICAL
//  ldr r10, [r0, #RCSR_OFFSET]
//  mov r2, #( RCSR_SLEEP_RESET + RCSR_GPIO_RESET)
//  tst     r10, r2
//  bne     12f                /* skip if sleep (or GPIO) reset. */
//The above is added by Bill Chen
//The following is modified by Bill Chen
#if 0
        ldr     r1, =0xa0000000
    str     r1, [r1]
    str     r1, [r1]
    str     r1, [r1]
    str     r1, [r1]
    str     r1, [r1]
    str     r1, [r1]
    str     r1, [r1]
    str     r1, [r1]

    str     r1, [r1]              @   Fix for erratum #116. Makes up for ineffective 1st mem access.
#endif

        ldr     r1, =0xa0000000
    ldr     r0, [r1]
    ldr     r0, [r1]
    ldr     r0, [r1]
    ldr     r0, [r1]
    ldr     r0, [r1]
    ldr     r0, [r1]
    ldr     r0, [r1]
    ldr     r0, [r1]

    ldr     r0, [r1]              @   Fix for erratum #116. Makes up for ineffective 1st mem access.
    @   This is being left in for PXA27x for the moment
    @
12:
    @  ***** STEP 8 *****
    @
    @   Re-enable D-cache if desired (we don't)

    @
    @  ***** STEP 9 *****
    @
    @  Re-enable SDRAM partitions
    @
        ldr     r2,  [r4, #0x0]       @  Fetch the current MDCNFG value
    orr     r2, r2, #0x80         @ Bill Chen 20060213
        orr     r2,  r2,  #0x1        @  Enable SDRAM bank 0
        str     r2,  [r4, #0x0]       @  Write back MDCNFG, enabling the SDRAM bank(s)
    @
    @  ***** STEP 10 *****
    @
    @  Write the MDMRS register to trigger an MRS command to all enabled banks of SDRAM.
    @
    @
    ldr     r1,  =0x0             @  Fetch platform MDMRS value
    str     r1,  [r4, #0x40]      @  Write the MDMRS value back
    @
    @  ***** STEP 11 *****
    @
    @  In systems with SDRAM or Synchronous Flash, optionally enable auto-power-down by setting MDREFR: APD
    @
        ldr     r3,  [r4, #0x04]      @  Get MDREFR value
        orr     r3,  r3,  #0x00100000 @  enable auto power down
        str     r3,  [r4, #0x04]      @  Write value back

//The followign is added by Bill Chen 20060320
#if 0
    /***********************************************************************/
    /*******************      initialize the power manager  ****************/
    /***********************************************************************/
    ldr     r0,  =PWR_BASE_PHYSICAL
    mov     r1, #PCFR_OPDE      // 0 - Don't stop 13Mhz oscillator during standby, sleep or deep-sleep mode
                        // 1 - Stop 13Mhz oscillator during standby, sleep or deep-sleep mode
#if 1
    orr     r1, r1, #PCFR_SYSEN_EN  // According to PXA270 Dev. Manual, it's reserved bit.
                        // Does it have special feature ?
#endif
    str     r1, [r0, #PCFR_OFFSET]

#endif

    /*********************************************************************/
    /*        Check to see if we're coming out of sleep reset.           */
    /*           Read & Init Reset Cause bits in RCSR.                   */
    /*             r10 has reset case bits value                         */
    /*********************************************************************/

    ldr     r0,  =PWR_BASE_PHYSICAL
    ldr     r10, [r0, #RCSR_OFFSET]

    /* extract the reset cause bits */
#if 1   /*
     * RCSR_ALL values was defined as 0x1F, But, it should be 0x0F
     */
    mov     r2,  #(RCSR_ALL & ~(0x2))       // Mask RCSR except WDR
#endif
    and     r10,  r10,  r2      // r10 now holds the conditioned Reset Reason

    /* clear the reset cause bits (they're sticky) */
    str     r2,  [r0, #RCSR_OFFSET]


    /************************************************************************/
    /*          if it's a sleep-reset, Jump back to the before sleep        */
    /*                  it might be Linux Kernel code                       */
    /************************************************************************/
    teq     r10, #RCSR_SLEEP_RESET
    bne     19f
    b       WakeUp

WakeUp:
    ldr r1, =PWR_BASE_PHYSICAL
    ldr r0, [r1, #PSPR_OFFSET]
    mov     pc, r0

19:
@  The following is added by Bill Chen 20060608
      ldr     r0, =0x40F00000                       @ set PMRCREGS PHYSICAL BASE
      mov     r2, #(0x10 | 0x20)                    @ Set the PH and RDH bits to enable all GPIOs
      str     r2, [r0, #0x04]                   @ Enable all GPIO lines
@ The above is added by Bill Chen 20060608

        mov     pc, lr                @  Return to calling program

//The above is added by Bill Chen 20060320

@ ******************************************************
@
@ NOTE: On system reset, all interrupts should be cleared by hardware.
@       This enforces disabling of all interrupts to HW boot default conditions.
@
Init_INT:

        ldr     r4,  =0x40d00000                @ Load interrupt controller physical base address
        ldr     r2,  =0x0                                       @ zero out a work register
        str     r2,  [r4, #0x04]                    @ Mask all interrupts (clear mask register)
        str     r2,  [r4, #0xa0]                    @ Mask all interrupts (clear mask register) 2
        str     r2,  [r4, #0x08]                    @ Clear the interrupt level register
        str     r2,  [r4, #0xa4]                    @ Clear the interrupt level register 2
        str     r2,  [r4, #0x14]                    @ Clear Interrupt Control Register
        str     r2,  [r4, #0xa8]                    @ Clear Interrupt Control Register 2
        mov     pc,  lr                                         @ return to calling routine

@*********************************************************************************************
@*********************************************************************************************

@********************************************************************************************
@
@ **********************************************
@ **********                          **********
@ ********** INITIALIZE CLOCK MANAGER **********
@ **********                          **********
@ **********************************************
@
@ Disable the peripheral clocks, and set the core clock frequency
@
@ NOTE: The Change Frequency Sequence should be called after this function in order
@       for the clock frequencies set in the CCCR register to take effect.
@
@       The code then spins on the oscillator OK bit until the oscilator is stable
@       which can take as long as two seconds.
@

Init_Clocks:

@ Turn Off ALL on-chip peripheral clocks for re-configuration
@
        ldr     r4,  =0x41300000                    @ Load clock registers base address
        ldr     r1,  =0x400000                      @ Forces memory clock to stay ON!!
        ldr     r2,  =0x00400220                    @ Get any other bits required from the include file
        orr     r1,  r1,  r2                        @ OR everything together
        str     r1,  [r4, #0x04]                    @ ... and write out to the clock enable register
@
@ Set Crystal: Memory Freq, Memory:RunMode Freq, RunMode, TurboMode Freq Multipliers,
@ set RunMode & TurboMode to default frequency.
@
        ldr     r2,  =0x00000110                    @ Get CORE_CLK_DEFAULT value
        str     r2,  [r4, #0x00]                    @ Write to the clock config register
@
@ Enable the 32 KHz oscillator and set the 32KHz output enable bits
@

        @mov     r1,  #(0x02 :OR: 0x04)
        mov r1,  #0x6
    str     r1,  [r4, #0x08]                    @ for RTC and Power Manager
@
@ Init Real Time Clock (RTC) registers
@
        ldr     r4,  =0x40900000                    @ Load RTC registers base address
        mov     r2,  #0                             @ Clear a work register
        str     r2,  [r4, #0x08]                    @ Clear RTC Status register
        str     r2,  [r4, #0x00]                    @ Clear RTC Counter Register
        str     r2,  [r4, #0x04]                    @ Clear RTC Alarm Register
        str     r2,  [r4, #0x28]                    @ Clear Stopwatch Counter Register
        str     r2,  [r4, #0x2c]                    @ Clear Stopwatch Alarm Register 1
        str     r2,  [r4, #0x30]                    @ Clear Stopwatch Alarm Register 2
        str     r2,  [r4, #0x34]                    @ Clear Periodic Counter Register
        str     r2,  [r4, #0x38]                    @ Clear Interrupt Alarm Register
@       mov     pc,  lr                             @ DISABLED - Return here if A0 silicon
@
@ Check the Oscillator OK (OOK) bit in clock register OSCC to insure the timekeeping oscillator
@ is enabled and stable before returning to the calling program.
@
@ The following is commented by Bill Chen 20060627

@        ldr     r4,  =0x41300000                   @ Reload clock registers base address
@xlli_6:
@        ldr     r1,  [r4, #0x08]                   @ Get the status of the OSCC register
@        ands    r1,  r1,  #0x01                        @ is the oscillator OK bit set?
@        beq     xlli_6                             @ Spin in this loop until the bit is set



@
@ Frequence change
@ initiates the frequency change sequence
@ and restarts the memory controller
@

        mrc     p14, 0, r2, c6, c0, 0               @ Get present status (preserve Turbo and Fast Bus bits)
        orr     r2,  r2,  #2                        @ Set the F bit
        mcr     p14, 0, r2, c6, c0, 0               @ initiate the frequency change sequence - Wheeeeeeeee!
@
@       If the clock frequency is chaged, the MDREFR Register must be  rewritten, even
@       if it's the same value. This will result in a refresh being performed and the
@       refresh counter being reset to the reset interval. (Section 13.10.3, pg 13-17 of EAS)
@
        ldr     r4,  =0x48000000                    @ Get memory controller base address
        ldr     r1,  [r4, #0x04]                    @ Get the current state of MDREFR
        str     r1,  [r4, #0x04]                    @ Re-write this value


        mov     pc,  lr                             @ return to calling routine


@*********************************************************************************************
@*********************************************************************************************


xlli_setClocks:

    mov     pc, lr                              @ Return to calling program

@*********************************************************************************************
@*********************************************************************************************


xlli_freq_change:
    mov     pc, lr                              @ Return to calling program

@*********************************************************************************************
@*********************************************************************************************


/* Nam9, 2004. 9. 17 */

    .align 4
bss_start:  .word   ___bss_start
bss_end :   .word   ___bss_end

@ addresses
blob_stack_pointer:     .long   (0xA4000000 - 4)
blob_ram_base_addr:     .long   0xA3C00000

    .align 2
str_init:   .ascii  "I\n\r\x00"

    .align 2
str_cpspl:         .ascii  "C\n\r\x00"

    .align 2
str1:          .ascii  "1\n\r\x00"

    .align 2
str2:             .ascii  "2\n\r\x00"

    .align 2
str3:             .ascii  "3\n\r\x00"

    .align 2
str4:             .ascii  "4\n\r\x00"
    .align 4
    .set M_START, RAM_START
    .set M_BOOT_LOADER_AREA_START_OFFSET_FROM_RAM_START, RAM_BOOT_LOADER_AREA_START_OFFSET_FROM_RAM_START
    .set M_BOOT_LOADER_AREA_LENGTH, RAM_BOOT_LOADER_AREA_LENGTH
    .set M_STACK_END_OFFSET_FROM_RAM_START, RAM_STACK_END_OFFSET_FROM_RAM_START
.ltorg
.org 0x7f0
magic:      .word ELDR_MAGIC
reserved1:  .word 0
reserved2:  .word 0
eldr_size:  .word _eldr_size

